package service

import (
	"context"
	"errors"
	"gitee.com/tietang/terrace-go/v2/base/starter/idbx"
	"gitee.com/tietang/terrace-go/v2/base/starter/ivalidator"
	"gitee.com/tietang/terrace-go/v2/example/order"
	"gitee.com/tietang/terrace-go/v2/example/order/domain"
	"gitee.com/tietang/terrace-go/v2/example/order/repo"
	_ "gitee.com/tietang/terrace-go/v2/example/order/service/exts"
	log "github.com/sirupsen/logrus"
	"github.com/tietang/dbx"
	"sync"
	"time"
)

var once sync.Once

func init() {
	once.Do(func() {
		service := new(orderService)
		service.proxy = new(order.CreateOrderServiceExtProxy)
		order.IOrderService = service
	})
}

type orderService struct {
	proxy order.CreateOrderServiceExt
}

func (o *orderService) Create(dto order.OrderCreatedDTO) (resp *order.OrderDTO, err error) {
	//验证输入参数
	if err = ivalidator.ValidateStruct(&dto); err != nil {
		return nil, err
	}
	eo := new(order.OrderDTO)
	eo.FromCreatedDTO(&dto)
	ctx := context.Background()
	if err = o.proxy.OnValidate(ctx, eo); err != nil {
		return nil, err
	}
	eo.Status = 0
	eo.BizDate = time.Now()
	//前置扩展点
	if err = o.proxy.Pre(ctx, eo); err != nil {
		return nil, err
	}
	do := domain.NewOrderDomain()
	do.Order = *domain.FromDTO(eo)
	err = idbx.Tx(func(runner *dbx.TxRunner) error {
		do.Repo = &repo.OrderDao{Runner: runner}
		if do.Id, err = do.Create(); err != nil {
			return err
		}
		order := do.Get()
		resp = domain.ToDTO(*order)
		return nil
	})
	if err != nil {
		log.Error(err)
	}
	//后置扩展点
	err = o.proxy.Post(ctx, eo, resp)
	return resp, err
}

func (o *orderService) ChangeStatus(dto order.OrderChangeStatusDTO) (status order.OrderChangeStatus, err error) {
	//验证输入参数
	if err := ivalidator.ValidateStruct(&dto); err != nil {
		return order.OrderChangeFailure, err
	}

	err = idbx.Tx(func(runner *dbx.TxRunner) error {
		do := domain.NewOrderDomain()
		do.Repo = &repo.OrderDao{Runner: runner}
		do.TradeNo = dto.TradeNo
		do.Status = dto.Status

		ok := do.ChangeStatus()
		if ok {
			return nil
		}
		return errors.New("")
	})

	if err == nil {
		return order.OrderChangeSuccess, nil
	}
	return order.OrderChangeFailure, err
}

func (o *orderService) Get(tradeNo string) (resp *order.OrderDTO) {
	idbx.Tx(func(runner *dbx.TxRunner) error {
		do := domain.NewOrderDomain()
		do.Repo = &repo.OrderDao{Runner: runner}
		do.TradeNo = tradeNo
		order := do.GetByTradeNo()
		resp = domain.ToDTO(*order)
		return nil
	})
	return resp
}
